/* eslint-disable react-hooks/exhaustive-deps */
import {useNavigate} from 'react-router-dom'
import './exhibition.css'
import {useRef,useEffect, useState} from 'react';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';//引入GLTFLoader 用于加载gltf文件
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';//引入OrbitControls 用于控制相机 旋转 轨道控制器
import {TextureLoader} from 'three/src/loaders/TextureLoader'//引入TextureLoader 用于加载贴图
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';//引入TransformControls 用于控制图片的位置 支持鼠标点击
import { Raycaster, Vector3 } from 'three';//引入Raycaster 用于检测简单碰撞
import imglist from '../../../public/3Dzlg/data'
import { Reflector } from 'three/examples/jsm/objects/Reflector.js';

function Exhibition() {
    const cameraSpeed = 0.1;//相机移动速度
    const boxRef:any = useRef(null);//拿到dom元素
    let animate:any;
    const navigate = useNavigate();
    let scene = new THREE.Scene();//场景
    let camera:any;//相机
    let renderer:any;//渲染器
    let controls:any;//控制相机
    let loader:any;//加载器
    let transformControls:any//控制图片的位置
    let raycaster:any
    let cameraDirection:any ;
    const creatBox=(data:any)=>{
        return new Promise((resolve:any, reject:any)=>{
            const box = new THREE.BoxGeometry(data.w, data.g, data.k)//方块几何体
            const mat = new THREE.MeshBasicMaterial()//方块的材质 用于声明材质 颜色 线框等 
             const texture =  new TextureLoader()//方块的贴图 webgl不能加载本地图片 所以需要用TextureLoader加载图片
             texture.load(new URL(data.url, import.meta.url).href, (texture:any)=>{
                mat.map = texture //texture是加载成功后的贴图对象
                const mesh = new THREE.Mesh(box, mat)//方块网格 作用是将方块的几何体和材质绑定在一起
                mesh.name = data.url//给网格添加名字 方便后面控制
                mesh .position.set(data.x, data.y, data.z)//方块位置
                mesh.rotation.y=Math.PI*data.edg//方块旋转角度
                // transformControls.attach(mesh);//将方块添加到transformControls中
                mesh.castShadow = true; // 允许投射阴影
                resolve(mesh)
             })
        })
    }
    useEffect(()=>{
        camera = new THREE.PerspectiveCamera(75, boxRef.current.clientWidth / boxRef.current.clientHeight, 1, 150);//相机
        camera.position.set(10, 6, 0)//相机位置
        const ambientLight = new THREE.PointLight(0xffffff, 0.5);//环境光
        scene.add(ambientLight);//添加环境光
        
        // 创建地板
        const floorGeometry = new THREE.PlaneGeometry(100, 100); // 地板几何体
        const floorReflector = new Reflector(floorGeometry, {
        color: 0xaaaaaa,
        textureWidth: 1024,
        textureHeight: 1024,
        clipBias: 0.003,
        }); // 创建 Reflector 进行倒影
        floorReflector.rotation.x = -Math.PI / 2;//地板旋转
        floorReflector.position.set(0, 0.01, 0); // 设置地板位置
        // floorReflector.receiveShadow = true; // 允许接收阴影
        scene.add(floorReflector);//添加地板到场景中
        //创建光源 
        const light = new THREE.DirectionalLight(0xffffff, 1);
        light.position.set(20, 20, 20).normalize(); // 设置光源位置
        // light.castShadow = true; // 允许投射阴影
        scene.add(light);//添加光源到场景中
        //渲染器
        renderer = new THREE.WebGLRenderer({ //渲染场景并将场景渲染到dom元素中
            antialias: true, // 抗锯齿
        });
        renderer.setSize(boxRef.current.clientWidth, boxRef.current.clientHeight);//渲染器大小
        boxRef.current.appendChild(renderer.domElement);//将渲染器添加到dom元素中
        //定义函数 用于处理窗口大小变化
        const handleResize = () => {
            const width = boxRef.current.clientWidth;
            const height = boxRef.current.clientHeight;
            renderer.setSize(width, height);
            camera.aspect = width / height;//相机的宽高比
            camera.updateProjectionMatrix();
        };
        window.addEventListener('resize', handleResize);//监听窗口大小变化调用函数
        loader = new GLTFLoader();//加载器
        
        controls =new OrbitControls(camera, renderer.domElement);//允许键盘控制相机

        transformControls =new TransformControls(camera, renderer.domElement);//控制图片的位置
        transformControls.setSpace('local');//设置坐标系以局部坐标系为准

        controls.enableDamping = true;//开启阻尼
        controls.dampingFactor = 0.05;//阻尼系数
        controls.rotateSpeed = 0.5;//旋转速度
        controls.screenSpacePanning = true;//允许平移
        // controls.target.set(position.x, position.y, position.z)//控制相机的目标点，以自身为目标

        //加载空间模型
        loader.load(new URL("../../../public/3Dzlg/scene_collision.glb", import.meta.url).href,(gltf:any)=>{
            const model = gltf.scene;//获取模型
            //起名字
            model.name = 'qiang'//用于控制碰撞
            scene.add(model);//添加模型到场景中
            animate()
        },undefined,(err:any)=>{console.log(err,'errrrr')})
        //加载杂物模型
        loader.load(new URL("../../../public/3Dzlg/scene_desk_obj.glb", import.meta.url).href,(gltf:any)=>{
            const model = gltf.scene;//获取模型
            //起名字
            model.name = 'diannao'//用于控制碰撞
            scene.add(model);//添加模型到场景中
        },undefined,(err:any)=>{console.log(err,'errrrr')})


        
        const velocity = new THREE.Vector3(0,0,0);//速度
        raycaster = new Raycaster();//碰撞检测器
        cameraDirection = new THREE.Vector3() //相机方向
     
        //添加所有图片
        imglist.forEach((item:any)=>{
            creatBox(item).then((res:any)=>{
            scene.add(res)
        })
        })
        let isMovingForward = false;//是否正在前进
        let isMovingBackward = false;//是否正在后退
        let isMovingLeft = false;//是否正在左移
        let isMovingRight = false;//是否正在右移
        const handleKeyDown = (event:any) => {
        switch (event.key) {
            case 'w':
                isMovingForward = true;
                break;
            case 's':
                console.log(isMovingBackward,'s1')
                isMovingBackward = true;
                break;
            case 'a':
                isMovingLeft = true;
                break; 
            case 'd':
                isMovingRight = true;
                break; 
             case 'q':
                console.log('q')
                break;    
        }
    };

    const handleKeyUp = (event:any) => {
        switch (event.key) {
            case 'w':
                isMovingForward = false;
                break;
            case 's':
                console.log(isMovingBackward,'s')
                isMovingBackward = false;
                break;
            case 'a':
                isMovingLeft = false;
                break;
            case 'd':
                isMovingRight = false;
                break;
        }
    };

        window.addEventListener('keydown', handleKeyDown);//监听键盘按下事件
        window.addEventListener('keyup', handleKeyUp);//监听键盘松开事件
        
        //定义动画函数
        animate = () => {
            
        // transformControls.update();//更新图片的位置
        const direction = new THREE.Vector3();//new THREE.Vector3()的作用是创建一个新的向量
        camera.getWorldDirection(direction);//获取相机的方向向量
        direction.y = 0;//将y轴方向设为0 避免相机上下抖动
        direction.normalize();//设置向量 使其长度为1 方便计算

        // 更新速度以根据按键状态移动
        velocity.set(0, velocity.y, 0); // 重置速度 作用是防止按键按住不动的情况 出现一直加速的情况
                             //add方法的作用是向量相加
        if (isMovingForward) velocity.add(direction.clone().multiplyScalar(cameraSpeed));//前进
                                         //sub方法的作用是向量相减
        if (isMovingBackward) velocity.sub(direction.clone().multiplyScalar(cameraSpeed));//后退
        const right = new THREE.Vector3();//new THREE.Vector3()的作用是创建一个新的向量
        // 右侧方向.crossVectors()函数的作用是求两个向量叉乘
        right.crossVectors(direction, new THREE.Vector3(0, 1, 0));
        if (isMovingLeft) velocity.add(right.clone().multiplyScalar(-cameraSpeed));//左移
        if (isMovingRight) velocity.add(right.clone().multiplyScalar(cameraSpeed));//右移
       
            // 碰撞检测
        // 进行射线检测
        raycaster.ray.origin.copy(camera.position); // 设置射线起点为相机的位置
        raycaster.ray.direction.copy(direction); // 设置射线的方向

        const distance = 5; // 最大检测距离（可以根据需要设置更大或更小）
        // 检测与墙壁（qiang对象）碰撞
        const intersects = raycaster.intersectObject(scene.getObjectByName('qiang'));
         // 如果碰撞，停止相机的前进或后退
    if (intersects.length > 0 && intersects[0].distance < distance) {
        const intersect = intersects[0]; // 获取第一个碰撞点
        console.log(intersect,'intersect.distance')
        // 计算碰撞点和相机之间的距离，停止相机继续移动
        if (isMovingForward) {
            isMovingForward = false;
            velocity.set(0, velocity.y, 0); // 停止前进
            camera.position.copy(intersect.point); // 将相机位置设置为碰撞点
        }

        if (isMovingBackward) {
            velocity.set(0, velocity.y, 0); // 作用是防止按键按住不动的情况 出现一直减速的情况
            camera.position.copy(intersect.point); // 将相机位置设置为碰撞点
        }
    }
            //方块位置跟随相机
            // mesh.position.copy(camera.position)
            // mesh.position.y += 1.5
             // 移动相机
            camera.position.add(velocity);//相机位置
            controls.target.copy(camera.position.clone().add(direction));//控制相机的目标点，以自身为目标
            //浏览器api 创建一个动画效果 在浏览器刷新一次屏幕以后执行一次
            requestAnimationFrame(animate);//渲染动画
            // controls.update();//更新控制相机
            renderer.render(scene, camera);//渲染场景
        };
        return ()=>{
            controls.dispose();//移除控制相机
        }
    },[])
    // const btn=()=>{
    //     audioRef.current.play()
    //     setFlag(true)
    // }
    return <div className="zhanting">
        {/* <button className="zhanting-btn" onClick={() => navigate('/music')}>《</button> */}
         <div id='zhanting' ref={boxRef}></div>
    </div>
}

export default Exhibition; 